home *** CD-ROM | disk | FTP | other *** search
/ SunSoft Catalyst CDWARE 1996 May to August / Catalyst CDWARE 1996 May to August.iso / .products / .bin / httpd / src / util.c < prev   
C/C++ Source or Header  |  1995-05-18  |  27KB  |  1,163 lines

  1. /*
  2.  * util.c: string utility things, and other utilities
  3.  * 
  4.  * All code contained herein is covered by the Copyright as distributed
  5.  * in the README file in the main directory of the distribution of 
  6.  * NCSA HTTPD.
  7.  *
  8.  * 03-23-93  Rob McCool
  9.  *     Original code up to version 1.3 from Rob McCool
  10.  *
  11.  * 02-16-95  cvarela
  12.  *    Fixed stack hole in strsubfirst
  13.  *
  14.  * 03-06-95  blong
  15.  *    Added inststr from bdflush-1.5 for Linux to set the name of
  16.  *    the running processes
  17.  *
  18.  * 03-10-95  blong
  19.  *    Added buffered getline for all but POST requests as suggested by
  20.  *    Robert S. Thau (rst@ai.mit.edu)
  21.  *
  22.  * 03-20-95  blong & cvarela
  23.  *    Fixed make_env_str so that it doesn't modify the pointers
  24.  *
  25.  * 04-03-95  blong
  26.  *    May have fixed problems (esp. under Solaris 2.3) with playing
  27.  *    with library memory in get_remote_name
  28.  *
  29.  * 04-13-95  guillory
  30.  *    added strncpy_dir that limits the length of a directory copy
  31.  *    also added strncpy for same reason
  32.  *
  33.  * 04-29-95  blong
  34.  *    added patch by Kevin Steves (stevesk@mayfield.hp.com) for inststr
  35.  *    under HPUX which uses the pstat command
  36.  */
  37.  
  38.  
  39. #include "httpd.h"
  40. #include <setjmp.h>
  41. #ifdef HPUX
  42. #include <sys/pstat.h>
  43. #endif
  44.  
  45. extern JMP_BUF jmpbuffer;
  46. extern char** environ;
  47.  
  48. /* modified from bdflush-1.5 for Linux source code 
  49.    This is used to set the name of the running process */
  50. void inststr(char *dst[], int argc, char *src)
  51. {
  52.  
  53. #ifdef HPUX
  54.  /*
  55.   * 4/29/95 Kevin Steves <stevesk@mayfield.hp.com>
  56.   * Use pstat(PSTAT_SETCMD) on HP-UX.
  57.   */
  58.      union pstun pst;
  59.  
  60.      pst.pst_command = src;
  61.      pstat(PSTAT_SETCMD, pst, 0, 0, 0);
  62. #else
  63.  
  64.     if (strlen(src) <= strlen(dst[0]))
  65.     {
  66.         char *ptr;
  67.  
  68.         for (ptr = dst[0]; *ptr; *(ptr++) = '\0');
  69.  
  70.         strcpy(dst[0], src);
  71.     } else
  72.     {
  73.         /* stolen from the source to perl 4.036 (assigning to $0) */
  74.         char *ptr, *ptr2;
  75.         int count;
  76.         ptr = dst[0] + strlen(dst[0]);
  77.         for (count = 1; count < argc; count++) {
  78.             if (dst[count] == ptr + 1)
  79.                 ptr += strlen(++ptr);
  80.         }
  81.         if (environ[0] == ptr + 1) {
  82.             for (count = 0; environ[count]; count++)
  83.                 if (environ[count] == ptr + 1)
  84.                     ptr += strlen(++ptr);
  85.         }
  86.         count = 0;
  87.         for (ptr2 = dst[0]; ptr2 <= ptr; ptr2++) {
  88.             *ptr2 = '\0';
  89.             count++;
  90.         }
  91.         strncpy(dst[0], src, count);
  92.     }
  93. #endif
  94. }
  95.  
  96. char *get_time() {
  97.     time_t t;
  98.     char *time_string;
  99.  
  100.     t=time(NULL);
  101.     time_string = ctime(&t);
  102.     time_string[strlen(time_string) - 1] = '\0';
  103.     return (time_string);
  104. }
  105.  
  106. char *gm_timestr_822(time_t sec) {
  107.     return ht_time(sec,HTTP_TIME_FORMAT, 1);
  108. }
  109.  
  110. char *ht_time(time_t t, char *fmt, int gmt) {
  111.     static char ts[MAX_STRING_LEN];
  112.     struct tm *tms;
  113.  
  114.     tms = (gmt ? gmtime(&t) : localtime(&t));
  115.  
  116.     /* check return code? */
  117.     strftime(ts,MAX_STRING_LEN,fmt,tms);
  118.     return ts;
  119. }
  120.  
  121. /* What a pain in the ass. */
  122. struct tm *get_gmtoff(long *tz) {
  123.     time_t tt;
  124.     struct tm *t;
  125.  
  126.     tt = time(NULL);
  127.     t = localtime(&tt);
  128. #if defined(BSD) && !defined(AUX) && !defined(APOLLO) && !defined(__QNX__)
  129.     *tz = t->tm_gmtoff;
  130. #else
  131.     *tz = - timezone;
  132.     if(t->tm_isdst)
  133.         *tz += 3600;
  134. #endif
  135.     return t;
  136. }
  137.  
  138.  
  139. static char *months[] = {
  140.     "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"
  141. };
  142.  
  143.  
  144. int find_month(char *mon) {
  145.     register int x;
  146.  
  147.     for(x=0;x<12;x++)
  148.         if(!strcmp(months[x],mon))
  149.             return x;
  150.     return -1;
  151. }
  152.  
  153. /* Roy owes Rob beer. */
  154. /* This would be considerably easier if strptime or timegm were portable */
  155.  
  156. int later_than(struct tm *lms, char *ims) {
  157.     char *ip;
  158.     char mname[MAX_STRING_LEN];
  159.     int year = 0, month = 0, day = 0, hour = 0, min = 0, sec = 0, x;
  160.  
  161.     /* Whatever format we're looking at, it will start with weekday. */
  162.     /* Skip to first space. */
  163.     if(!(ip = strchr(ims,' ')))
  164.         return 0;
  165.     else
  166.         while(isspace(*ip))
  167.             ++ip;
  168.  
  169.     if(isalpha(*ip)) {
  170.         /* ctime */
  171.         sscanf(ip,"%s %d %d:%d:%d %*s %d",mname,&day,&hour,&min,&sec,&year);
  172.     }
  173.     else if(ip[2] == '-') {
  174.         /* RFC 850 (normal HTTP) */
  175.         char t[MAX_STRING_LEN];
  176.         sscanf(ip,"%s %d:%d:%d",t,&hour,&min,&sec);
  177.         t[2] = '\0';
  178.         day = atoi(t);
  179.         t[6] = '\0';
  180.         strcpy(mname,&t[3]);
  181.         x = atoi(&t[7]);
  182.         /* Prevent wraparound from ambiguity */
  183.         if(x < 70)
  184.             x += 100;
  185.         year = 1900 + x;
  186.     }
  187.     else {
  188.         /* RFC 822 */
  189.         sscanf(ip,"%d %s %d %d:%d:%d",&day,mname,&year,&hour,&min,&sec);
  190.     }
  191.     month = find_month(mname);
  192.  
  193.     if((x = (1900+lms->tm_year) - year))
  194.         return x < 0;
  195.     if((x = lms->tm_mon - month))
  196.         return x < 0;
  197.     if((x = lms->tm_mday - day))
  198.         return x < 0;
  199.     if((x = lms->tm_hour - hour))
  200.         return x < 0;
  201.     if((x = lms->tm_min - min))
  202.         return x < 0;
  203.     if((x = lms->tm_sec - sec))
  204.         return x < 0;
  205.  
  206.     return 1;
  207. }
  208.  
  209.  
  210. /* Match = 0, NoMatch = 1, Abort = -1 */
  211. /* Based loosely on sections of wildmat.c by Rich Salz */
  212. int strcmp_match(char *str, char *exp) {
  213.     int x,y;
  214.  
  215.     for(x=0,y=0;exp[y];++y,++x) {
  216.         if((!str[x]) && (exp[y] != '*'))
  217.             return -1;
  218.         if(exp[y] == '*') {
  219.             while(exp[++y] == '*');
  220.             if(!exp[y])
  221.                 return 0;
  222.             while(str[x]) {
  223.                 int ret;
  224.                 if((ret = strcmp_match(&str[x++],&exp[y])) != 1)
  225.                     return ret;
  226.             }
  227.             return -1;
  228.         } else 
  229.             if((exp[y] != '?') && (str[x] != exp[y]))
  230.                 return 1;
  231.     }
  232.     return (str[x] != '\0');
  233. }
  234.  
  235. int is_matchexp(char *str) {
  236.     register int x;
  237.  
  238.     for(x=0;str[x];x++)
  239.         if((str[x] == '*') || (str[x] == '?'))
  240.             return 1;
  241.     return 0;
  242. }
  243.  
  244. void strsubfirst(int start,char *dest, char *src)
  245. {
  246.   int src_len, dest_len, i;
  247.  
  248.   if ((src_len=strlen(src))<start){  /** src "fits" in dest **/
  249.     for (i=0;dest[i]=src[i];i++);
  250.     for (i=src_len;dest[i]=dest[i-src_len+start];i++);
  251.   }
  252.   else {                             /** src doesn't fit in dest **/
  253.     for (dest_len=strlen(dest),i=dest_len+src_len-start;i>=src_len;i--)
  254.       dest[i] = dest[i-src_len+start];
  255.     for (i=0;i<src_len;i++) dest[i]=src[i];
  256.   }
  257. }
  258.  
  259. /*
  260.  * Parse .. so we don't compromise security
  261.  */
  262. void getparents(char *name)
  263. {
  264.     int l=0,w=0;
  265.     const char *lookfor="..";
  266.  
  267.     while(name[l]!='\0') {
  268.         if(name[l]!=lookfor[w]) (w>0 ? (l-=(w-1),w=0) : l++);
  269.         else {
  270.             if(lookfor[++w]=='\0') {
  271.                 if((name[l+1]=='\0') || (name[l+1]=='/') &&
  272.                    (((l > 3) && (name[l-2] == '/')) || (l<=3))) {
  273.                     register int m=l+1,n;
  274.  
  275.                     l=l-3;
  276.                     if(l>=0) {
  277.                         while((l!=0) && (name[l]!='/')) --l;
  278.                     }
  279.                     else l=0;
  280.                     n=l;
  281.                     while(name[n]=name[m]) (++n,++m);
  282.                     w=0;
  283.                 }
  284.                 else w=0;
  285.             }
  286.             else ++l;
  287.         }
  288.     }
  289. }
  290.  
  291. void no2slash(char *name) {
  292.     register int x,y;
  293.  
  294.     for(x=0; name[x]; x++)
  295.         if(x && (name[x-1] == '/') && (name[x] == '/'))
  296.             for(y=x+1;name[y-1];y++)
  297.                 name[y-1] = name[y];
  298. }
  299.  
  300. void make_dirstr(char *s, int n, char *d) {
  301.     register int x,f;
  302.  
  303.     for(x=0,f=0;s[x];x++) {
  304.         if((d[x] = s[x]) == '/')
  305.             if((++f) == n) {
  306.                 d[x] = '\0';
  307.                 return;
  308.             }
  309.     }
  310.     d[x] = '\0';
  311. }
  312.  
  313. int count_dirs(char *path) {
  314.     register int x,n;
  315.  
  316.     for(x=0,n=0;path[x];x++)
  317.         if(path[x] == '/') n++;
  318.     return n;
  319. }
  320.  
  321.  
  322. void strcpy_dir(char *d, char *s) {
  323.    register int x;
  324.  
  325.    for(x=0;s[x];x++)
  326.        d[x] = s[x];
  327.  
  328.    if(s[x-1] != '/') d[x++] = '/';
  329.    d[x] = '\0';
  330. }
  331.  
  332. /*
  333.  * A version of strcpy_dir that limits the number of characters
  334.  * that will be copied to n - 1. If s is of length n or greater,
  335.  * that portion is not copied and d is null-terminated at position
  336.  * n. This fixes potential security hole in evaluate_acess.
  337.  * SSG 4/15/95
  338.  */
  339. void strncpy_dir(char *d, char *s, int n) {
  340.     register int x;
  341.     
  342.     for(x=0;s[x] && x < (n - 1);x++)
  343.         d[x] = s[x];
  344.  
  345.     if(s[x-1] != '/' && x < (n - 1)) d[x++] = '/';
  346.     d[x] = '\0';
  347. }
  348.  
  349. /*
  350.  * My version of strncpy. This will null terminate d if
  351.  * s is n characters or longer. It also will only copy
  352.  * n - 1 characters to d. SSG 4/13/95
  353.  */
  354. void lim_strcpy(char *d, char *s, int n) 
  355. {
  356.     while (--n && (*d++ = *s++))
  357.      ;
  358.  
  359.     if (!n) 
  360.       *d = '\0';
  361. }
  362.  
  363. void chdir_file(char *file) {
  364.     int i;
  365.  
  366.     if((i = rind(file,'/')) == -1)
  367.         return;
  368.     file[i] = '\0';
  369.     chdir(file);
  370.     file[i] = '/';
  371. }
  372.  
  373. void http2cgi(char *w) {
  374.     register int x;
  375.  
  376.     for(x=strlen(w);x != -1; --x)
  377.         w[x+5]= (w[x] == '-' ? '_' : toupper(w[x]));
  378.     strncpy(w,"HTTP_",5);
  379. }
  380.  
  381. void getline_timed_out() {
  382.     char errstr[MAX_STRING_LEN];
  383.  
  384.     sprintf(errstr,"timed out waiting for %s",remote_name);
  385.     log_error(errstr);
  386.     if (!standalone) {
  387.     fclose(stdin);
  388.     fclose(stdout);
  389.     exit(0);
  390.     } else {
  391.         if (remote_name) {
  392.         free(remote_name);
  393.         remote_name = NULL;
  394.         }
  395.         if (remote_host) {
  396.         free(remote_host);
  397.         remote_host = NULL;
  398.         }
  399. /* Don't free it, its system memory */ 
  400. /*        if (remote_ip) {
  401.         free(remote_ip);
  402.         remote_ip = NULL;
  403.         } */
  404. #if defined(NeXT) || defined(__mc68000__)
  405.     longjmp(jmpbuffer,1);
  406. #else
  407.         siglongjmp(jmpbuffer,1);
  408. #endif
  409.     }
  410. }
  411.  
  412. /* Original, mostly brain dead version
  413.  
  414. int getline(char *s, int n, int f, unsigned int timeout) {
  415.     register int i=0, ret;
  416.  
  417.     signal(SIGALRM,getline_timed_out);
  418.     alarm(timeout);
  419.     while(1) { 
  420.         if((ret = read(f,&s[i],1)) <= 0) {
  421.             /* Mmmmm, Solaris.  */
  422. /*            if((ret == -1) && (errno == EINTR))
  423.                 continue;
  424.             s[i] = '\0';
  425.             return 1;
  426.         }
  427.  
  428.         if(s[i] == CR)
  429.             read(f,&s[i],1);
  430.  
  431.         if((s[i] == LF) || (i == (n-1))) {
  432.             alarm(0);
  433.             signal(SIGALRM,SIG_IGN);
  434.             s[i] = '\0';
  435.             return 0;
  436.         }
  437.         ++i;
  438.     }
  439. } */
  440.  
  441. /* Fixed, from Robert Thau
  442. /* An awkward attempt to fix the single-character-read braindamage
  443.  * which Rob McCool has described as the worst implementation decision
  444.  * of his entire life...
  445.  *
  446.  * Unfortunately, there is no easy fix for CGI POSTs unless we want to
  447.  * break NPH scripts (which we might).  However, all current GET
  448.  * transactions can be buffered without fear.  So, let's try that and
  449.  * see what happens.
  450.  *
  451.  * If the first four characters read off the socket are "GET ", we do
  452.  * buffering.  Otherwise, we keep the original brain-damaged behavior.
  453.  *
  454.  * rst, 11/4/94
  455.  *
  456.  * Further hacked to not set the timeout alarm unless we are actually
  457.  * reading from the socket.  (All those alarm() calls do add up).
  458.  *
  459.  * rst, 1/23/95
  460.  */
  461.  
  462. int getline_seen_cmd = 0;
  463. char getline_buffer[HUGE_STRING_LEN];
  464. int getline_buffered_fd = -1;
  465.  
  466. static int getline_buf_posn;
  467. static int getline_buf_good;
  468.  
  469. int getline_read_buf(char *s, int n, unsigned int timeout)
  470. {
  471.   char *endp = s + n - 1;
  472.   int have_alarmed = 0;
  473.   int buf_posn = getline_buf_posn, buf_good = getline_buf_good;
  474.   int f = getline_buffered_fd;
  475.   int client_broke_off = 0;
  476.   int c = 0;                    /* Anything but LF */
  477.   
  478.   do
  479.   {
  480.     if (buf_posn == buf_good)
  481.     {
  482.       int ret;
  483.  
  484.       have_alarmed = 1;
  485.       signal(SIGALRM,getline_timed_out);
  486.       alarm(timeout);
  487.       
  488.       if ((ret=read(f, getline_buffer, sizeof(getline_buffer))) <= 0)
  489.       {
  490.         if (ret == -1 && errno == EINTR) continue; /* Solaris... */
  491.         else { client_broke_off = 1; break; }
  492.       }
  493.  
  494.       buf_good = ret;
  495.       buf_posn = 0;
  496.     }
  497.     
  498.     c = getline_buffer[buf_posn++];
  499.  
  500.     if (c == LF) break;
  501.     if (c != CR) *s++ = c;
  502.   }
  503.   while (s < endp);
  504.   
  505.   if (have_alarmed) { alarm(0); signal(SIGALRM,SIG_IGN); }
  506.   
  507.   *s = '\0';
  508.   getline_buf_posn = buf_posn;
  509.   getline_buf_good = buf_good;
  510.   
  511.   return client_broke_off;
  512. }
  513.  
  514. int getline(char *s, int n, int f, unsigned int timeout) {
  515.     register int i=0, ret;
  516.  
  517.     if (f == getline_buffered_fd)
  518.       return getline_read_buf (s, n, timeout);
  519.     
  520.     signal(SIGALRM,getline_timed_out);
  521.     alarm(timeout);
  522.     while(1) {
  523.         if((ret = read(f,&s[i],1)) <= 0) {
  524.           /* Mmmmm, Solaris.  */
  525.           if((ret == -1) && (errno == EINTR))
  526.             continue;
  527.           s[i] = '\0';
  528.           return 1;
  529.         }
  530.  
  531.         if(s[i] == CR)
  532.             continue;           /* Get another character... */
  533.  
  534.         if((s[i] == LF) || (i == (n-1))) {
  535.             alarm(0);
  536.             signal(SIGALRM,SIG_IGN);
  537.             s[i] = '\0';
  538.             return 0;
  539.         }
  540.  
  541.         if (i == 3 && getline_seen_cmd == 0)
  542.         {
  543.           getline_seen_cmd = 1;
  544.           
  545.           if (!strncmp (s, "GET ", 4)) {
  546.             getline_buffered_fd = f;
  547.             getline_buf_posn = getline_buf_good = 0; /* Force read */
  548.             ret = getline_read_buf (s + 4, n - 4, timeout);
  549.             return ret;
  550.           }
  551.         }
  552.         
  553.         ++i;
  554.     }
  555. }
  556.  
  557. void getword(char *word, char *line, char stop) {
  558.     int x = 0,y;
  559.  
  560.     for(x=0;((line[x]) && (line[x] != stop));x++)
  561.         word[x] = line[x];
  562.  
  563.     word[x] = '\0';
  564.     if(line[x]) ++x;
  565.     y=0;
  566.  
  567.     while(line[y++] = line[x++]);
  568. }
  569.  
  570. void cfg_getword(char *word, char *line) {
  571.     int x=0,y;
  572.     
  573.     for(x=0;line[x] && isspace(line[x]);x++);
  574.     y=0;
  575.     while(1) {
  576.         if(!(word[y] = line[x]))
  577.             break;
  578.         if(isspace(line[x]))
  579.             if((!x) || (line[x-1] != '\\'))
  580.                 break;
  581.         if(line[x] != '\\') ++y;
  582.         ++x;
  583.     }
  584.     word[y] = '\0';
  585.     while(line[x] && isspace(line[x])) ++x;
  586.     for(y=0;line[y] = line[x];++x,++y);
  587. }
  588.  
  589. int eat_ws (FILE* fp)
  590. {
  591.     int ch;
  592.  
  593.     while ((ch = fgetc (fp)) != EOF) {
  594.         if (ch != ' ' && ch != '\t')
  595.             return ch;
  596.     }
  597.     return ch;
  598. }
  599.          
  600. int cfg_getline (char* s, int n, FILE* fp)
  601. {
  602.     int   len = 0, ch;
  603.  
  604.     ch = eat_ws(fp);
  605.     while (1) {
  606.         if (ch == EOF || ch == '\n' || (len == n-1)) {
  607.             if (len && s[len - 1] == ' ') s[len - 1] = '\0'; 
  608.             else s[len] = '\0';
  609.             return feof(fp) ? 1 : 0;
  610.         }
  611.         s[len++] = ch;
  612.         ch = fgetc (fp);
  613.         if (ch == '\t' || ch == ' ') {
  614.             s[len++] = ch;
  615.             ch = eat_ws (fp);
  616.         }
  617.     }
  618. }
  619.  
  620.  
  621. void escape_shell_cmd(char *cmd) {
  622.     register int x,y,l;
  623.  
  624.     l=strlen(cmd);
  625.     for(x=0;cmd[x];x++) {
  626.         if(ind("&;`'\"|*?~<>^()[]{}$\\",cmd[x]) != -1){
  627.             for(y=l+1;y>x;y--)
  628.                 cmd[y] = cmd[y-1];
  629.             l++; /* length has been increased */
  630.             cmd[x] = '\\';
  631.             x++; /* skip the character */
  632.         }
  633.     }
  634. }
  635.  
  636. void plustospace(char *str) {
  637.     register int x;
  638.  
  639.     for(x=0;str[x];x++) if(str[x] == '+') str[x] = ' ';
  640. }
  641.  
  642. void spacetoplus(char *str) {
  643.     register int x;
  644.  
  645.     for(x=0;str[x];x++) if(str[x] == ' ') str[x] = '+';
  646. }
  647.  
  648. char x2c(char *what) {
  649.     register char digit;
  650.  
  651.     digit = ((what[0] >= 'A') ? ((what[0] & 0xdf) - 'A')+10 : (what[0] - '0'));
  652.     digit *= 16;
  653.     digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A')+10 : (what[1] - '0'));
  654.     return(digit);
  655. }
  656.  
  657. void unescape_url(char *url) {
  658.     register int x,y;
  659.  
  660.     for(x=0,y=0;url[y];++x,++y) {
  661.         if((url[x] = url[y]) == '%') {
  662.             url[x] = x2c(&url[y+1]);
  663.             y+=2;
  664.         }
  665.     }
  666.     url[x] = '\0';
  667. }
  668.  
  669. #define c2x(what,where) sprintf(where,"%%%2x",what)
  670.  
  671. void escape_url(char *url) {
  672.     register int x,y;
  673.     char *copy;
  674.  
  675.     copy = strdup(url);
  676.             
  677.     for(x=0,y=0;copy[x];x++,y++) {
  678.         if(ind("% ?+&",url[y] = copy[x]) != -1) {
  679.             c2x(copy[x],&url[y]);
  680.             y+=2;
  681.         }
  682.     }
  683.     url[y] = '\0';
  684.     free(copy);
  685. }
  686.  
  687. void escape_uri(char *url) {
  688.     register int x,y;
  689.     char *copy;
  690.  
  691.     copy = strdup(url);
  692.             
  693.     for(x=0,y=0;copy[x];x++,y++) {
  694.         if(ind(":% ?+&",url[y] = copy[x]) != -1) {
  695.             c2x(copy[x],&url[y]);
  696.             y+=2;
  697.         }
  698.     }
  699.     url[y] = '\0';
  700.     free(copy);
  701. }
  702.  
  703. void make_full_path(char *src1,char *src2,char *dst) {
  704.     register int x,y;
  705.  
  706.     for(x=0;dst[x] = src1[x];x++);
  707.  
  708.     if(!x) dst[x++] = '/';
  709.     else if((dst[x-1] != '/'))
  710.         dst[x++] = '/';
  711.  
  712.     for(y=0;dst[x] = src2[y];x++,y++);
  713. }
  714.  
  715. int is_directory(char *path) {
  716.     struct stat finfo;
  717.  
  718.     if(stat(path,&finfo) == -1)
  719.         return 0; /* in error condition, just return no */
  720.  
  721.     return(S_ISDIR(finfo.st_mode));
  722. }
  723.  
  724. int is_url(char *u) {
  725.     register int x;
  726.  
  727.     for(x=0;u[x] != ':';x++)
  728.         if((!u[x]) || (!isalpha(u[x])))
  729.             return 0;
  730.  
  731.     if((u[x+1] == '/') && (u[x+2] == '/'))
  732.         return 1;
  733.     else return 0;
  734. }
  735.  
  736. char *make_env_str(char *name, char *value, FILE *out) {
  737.     char *t,*tp;
  738.     char *value2;
  739.     char *name2;
  740.     
  741.     value2 = value;
  742.     name2 = name;
  743.  
  744.     if(!(t = (char *)malloc(strlen(name)+strlen(value2)+2)))
  745.         die(NO_MEMORY,"make_env_str",out);
  746.  
  747.     for(tp=t;*tp = *name2;tp++,name2++);
  748.     for(*tp++ = '=';*tp = *value2;tp++,value2++);
  749.     return t;
  750. }
  751.  
  752. char* replace_env_str(char **env, char *name, char *value, FILE *out)
  753. {
  754.     register int i, len;
  755.  
  756.     for (i = 0, len = strlen(name); env[i]; i++) {
  757.     if (strncmp(env[i], name, len) == 0) {
  758.         free(env[i]);
  759.         env[i] = make_env_str(name, value, out);
  760.         return env[i];
  761.     }
  762.     }
  763. }
  764.  
  765.  
  766. char **new_env(char **env, int to_add, int *pos) {
  767.     if(!env) {
  768.         char **newenv;
  769.         *pos = 0;
  770.         newenv = (char **)malloc((to_add+1)*sizeof(char *));
  771.     newenv[to_add] = NULL;
  772.     return newenv;
  773.     }
  774.     else {
  775.         int x;
  776.  
  777.         for(x=0;env[x];x++)
  778.         ;
  779.  
  780.         if(!(env = (char **)realloc(env, (to_add+x+1)*(sizeof(char *)))))
  781.             return NULL;
  782.  
  783.     env[to_add + x] = NULL;
  784.         *pos = x;
  785.         return env;
  786.     }
  787. }
  788.  
  789. void free_env(char **env) {
  790.     int x;
  791.  
  792.     for(x=0;env[x];x++)
  793.         free(env[x]);
  794.     free(env);
  795.     env = NULL;
  796. }
  797.  
  798. int can_exec(struct stat *finfo) {
  799.     if(user_id == finfo->st_uid)
  800.         if(finfo->st_mode & S_IXUSR)
  801.             return 1;
  802.     if(group_id == finfo->st_gid)
  803.         if(finfo->st_mode & S_IXGRP)
  804.             return 1;
  805.     return (finfo->st_mode & S_IXOTH);
  806. }
  807.  
  808. #ifdef NEED_STRDUP
  809. char *strdup (char *str)
  810. {
  811.   char *dup;
  812.  
  813.   if(!(dup = (char *)malloc (strlen (str) + 1)))
  814.       return NULL;
  815.   dup = strcpy (dup, str);
  816.  
  817.   return dup;
  818. }
  819. #endif
  820.  
  821. /* The following two routines were donated for SVR4 by Andreas Vogel */
  822. #ifdef NEED_STRCASECMP
  823. int strcasecmp (const char *a, const char *b)
  824. {
  825.     const char *p = a;
  826.     const char *q = b;
  827.     for (p = a, q = b; *p && *q; p++, q++)
  828.     {
  829.       int diff = tolower(*p) - tolower(*q);
  830.       if (diff) return diff;
  831.     }
  832.     if (*p) return 1;       /* p was longer than q */
  833.     if (*q) return -1;      /* p was shorter than q */
  834.     return 0;               /* Exact match */
  835. }
  836.  
  837. #endif
  838.  
  839. #ifdef NEED_STRNCASECMP
  840. int strncasecmp (const char *a, const char *b, int n)
  841. {
  842.     const char *p = a;
  843.     const char *q = b;
  844.  
  845.     for (p = a, q = b; /*NOTHING*/; p++, q++)
  846.     {
  847.       int diff;
  848.       if (p == a + n) return 0;     /*   Match up to n characters */
  849.       if (!(*p && *q)) return *p - *q;
  850.       diff = tolower(*p) - tolower(*q);
  851.       if (diff) return diff;
  852.     }
  853.     /*NOTREACHED*/
  854. }
  855. #endif
  856.  
  857.  
  858.  
  859. #ifdef NEED_INITGROUPS
  860. int initgroups(const char *name, gid_t basegid)
  861. {
  862.   gid_t groups[NGROUPS_MAX];
  863.   struct group *g;
  864.   int index = 0;
  865.  
  866.   groups[index++] = basegid;
  867.  
  868.   while (index < NGROUPS_MAX && ((g = getgrent()) != NULL))
  869.     if (g->gr_gid != basegid)
  870.     {
  871.       char **names;
  872.  
  873.       for (names = g->gr_mem; *names != NULL; ++names)
  874.         if (!strcmp(*names, name))
  875.           groups[index++] = g->gr_gid;
  876.     }
  877.  
  878.   return setgroups(index, groups);
  879. }
  880. #endif
  881.  
  882. #ifdef __QNX__
  883. int setgroups(int index, gid_t *groups) {
  884.    index = index;
  885.    groups = groups;
  886.    return 0;
  887. }
  888. #endif
  889.  
  890. #ifdef NEED_WAITPID
  891. /* From ikluft@amdahl.com */
  892. /* this is not ideal but it works for SVR3 variants */
  893. /* httpd does not use the options so this doesn't implement them */
  894. int waitpid(pid_t pid, int *statusp, int options)
  895. {
  896.     int tmp_pid;
  897.     if ( kill ( pid,0 ) == -1) {
  898.         errno=ECHILD;
  899.         return -1;
  900.     }
  901.     while ((( tmp_pid = wait(statusp)) != pid) && ( tmp_pid != -1 ));
  902.     return tmp_pid;
  903. }
  904. #endif
  905.  
  906. int ind(char *s, char c) {
  907.     register int x;
  908.  
  909.     for(x=0;s[x];x++)
  910.         if(s[x] == c) return x;
  911.  
  912.     return -1;
  913. }
  914.  
  915. int rind(char *s, char c) {
  916.     register int x;
  917.  
  918.     for(x=strlen(s)-1;x != -1;x--)
  919.         if(s[x] == c) return x;
  920.  
  921.     return -1;
  922. }
  923.  
  924. void str_tolower(char *str) {
  925.     while(*str) {
  926.         *str = tolower(*str);
  927.         ++str;
  928.     }
  929. }
  930.         
  931. uid_t uname2id(char *name) {
  932.     struct passwd *ent;
  933.  
  934.     if(name[0] == '#') 
  935.         return(atoi(&name[1]));
  936.  
  937.     if(!(ent = getpwnam(name))) {
  938.         fprintf(stderr,"httpd: bad user name %s\n",name);
  939.         exit(1);
  940.     }
  941.     else return(ent->pw_uid);
  942. }
  943.  
  944. gid_t gname2id(char *name) {
  945.     struct group *ent;
  946.  
  947.     if(name[0] == '#') 
  948.         return(atoi(&name[1]));
  949.  
  950.     if(!(ent = getgrnam(name))) {
  951.         fprintf(stderr,"httpd: bad group name %s\n",name);
  952.         exit(1);
  953.     }
  954.     else return(ent->gr_gid);
  955. }
  956.  
  957. int get_portnum(int sd,FILE *out) {
  958.     struct sockaddr addr;
  959.     int len;
  960.  
  961.     len = sizeof(struct sockaddr);
  962.     if(getsockname(sd,&addr,&len) < 0)
  963.         die(SERVER_ERROR,"could not get port number",out);
  964.     return ntohs(((struct sockaddr_in *)&addr)->sin_port);
  965. }
  966.  
  967. char *find_fqdn(struct hostent *p) {
  968.     int x;
  969.  
  970.     if(ind(p->h_name,'.') == -1) {
  971.         for(x=0;p->h_aliases[x];++x) {
  972.             if((ind(p->h_aliases[x],'.') != -1) && 
  973.                (!strncmp(p->h_aliases[x],p->h_name,strlen(p->h_name))))
  974.                 return strdup(p->h_aliases[x]);
  975.         }
  976.         return NULL;
  977.     } else return strdup(p->h_name);
  978. }
  979.  
  980. void get_remote_host(int fd) {
  981.     struct sockaddr addr;
  982.     int len;
  983.     struct in_addr *iaddr;
  984.     struct hostent *hptr;
  985.  
  986.     len = sizeof(struct sockaddr);
  987.     if (remote_name) {
  988.     free(remote_name);
  989.     remote_name = NULL;
  990.     }
  991.     if (remote_host) {
  992.     free(remote_host);
  993.     remote_host = NULL;
  994.     }
  995. /* Don't free it, its system memory */
  996. /*    if (remote_ip) {
  997.     free(remote_ip);
  998.     remote_ip = NULL;
  999.     } */
  1000.  
  1001.     if ((getpeername(fd, &addr, &len)) < 0) {
  1002.     remote_name = (char *) malloc (sizeof(char)*13);
  1003.         strcpy(remote_name,"UNKNOWN_HOST");
  1004.         return;
  1005.     }
  1006.  
  1007.     iaddr = &(((struct sockaddr_in *)&addr)->sin_addr);
  1008. #ifndef MINIMAL_DNS
  1009.     hptr = gethostbyaddr((char *)iaddr, sizeof(struct in_addr), AF_INET);
  1010.     if(hptr) {
  1011.         remote_host = strdup(hptr->h_name);
  1012.         str_tolower(remote_host);
  1013.     if (remote_name) free(remote_name);
  1014.         remote_name = strdup(remote_host);
  1015.     }
  1016.     else 
  1017. #endif
  1018.         remote_host = NULL;
  1019.  
  1020. #ifdef MAXIMUM_DNS
  1021.     /* Grrr. Check THAT name to make sure it's really the name of the addr. */
  1022.     /* Code from Harald Hanche-Olsen <hanche@imf.unit.no> */
  1023.     if(remote_host) {
  1024.         char **haddr;
  1025.  
  1026.         hptr = gethostbyname(remote_host);
  1027.         if (hptr) {
  1028.             for(haddr=hptr->h_addr_list;*haddr;haddr++) {
  1029.                 if(((struct in_addr *)(*haddr))->s_addr == iaddr->s_addr)
  1030.                     break;
  1031.             }
  1032.         }
  1033.         if((!hptr) || (!(*haddr)))
  1034.         if (remote_host) {
  1035.         free(remote_host);
  1036.                 remote_host = NULL;
  1037.         }
  1038.     }
  1039. #endif
  1040.     remote_ip = inet_ntoa(*iaddr);
  1041.     if(!remote_host){
  1042.     if (remote_name) free(remote_name);
  1043.         remote_name = strdup(remote_ip);
  1044.     }
  1045.     if (!remote_name){
  1046.     remote_name = (char *) malloc (sizeof(char)*15);
  1047.         strcpy(remote_name,"UNKNOWN_HOST");
  1048.     }
  1049. }
  1050.  
  1051. char *get_remote_logname(FILE *fd) {
  1052.     int len;
  1053.     char *result;
  1054. #if defined(NeXT) || defined(LINUX) || defined(SOLARIS2) || defined(__bsdi__)
  1055.     struct sockaddr sa_server, sa_client;
  1056. #else
  1057.     struct sockaddr_in sa_server,sa_client;
  1058. #endif
  1059.  
  1060.     len = sizeof(sa_client);
  1061.     if(getpeername(fileno(stdout),&sa_client,&len) != -1) {
  1062.         len = sizeof(sa_server);
  1063.         if(getsockname(fileno(stdout),&sa_server,&len) == -1){
  1064.         result = (char *) malloc(sizeof(char)*8);
  1065.             strcpy(result, "unknown");
  1066.     }
  1067.         else
  1068.             result = rfc931((struct sockaddr_in *) & sa_client,
  1069.                                     (struct sockaddr_in *) & sa_server);
  1070.     }
  1071.     else {
  1072.     result = (char *) malloc(sizeof(char)*8);
  1073.         strcpy(result, "unknown");
  1074.     }
  1075.  
  1076.     return result; /* robm=pinhead */
  1077. }
  1078.  
  1079. void get_local_host()
  1080. {
  1081.     char str[128];
  1082.     int len = 128;
  1083.  
  1084.     if(!server_hostname) {
  1085.         struct hostent *p;
  1086.         gethostname(str, len);
  1087.         if((!(p=gethostbyname(str))) || (!(server_hostname = find_fqdn(p)))) {
  1088.             fprintf(stderr,"httpd: cannot determine local host name.\n");
  1089.             fprintf(stderr,"Use ServerName to set it manually.\n");
  1090.             exit(1);
  1091.         }
  1092.     }
  1093. }
  1094.  
  1095. void construct_url(char *d, char *s) {
  1096. /* Since 80 is default port */
  1097.   if (port == 80) {
  1098.     sprintf(d,"http://%s%s",server_hostname,s);
  1099.   } else {
  1100.     sprintf(d,"http://%s:%d%s",server_hostname,port,s);
  1101.   }
  1102. /*    escape_url(d); */
  1103. }
  1104.  
  1105. /* aaaack but it's fast and const should make it shared text page. */
  1106. const int pr2six[256]={
  1107.     64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  1108.     64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,62,64,64,64,63,
  1109.     52,53,54,55,56,57,58,59,60,61,64,64,64,64,64,64,64,0,1,2,3,4,5,6,7,8,9,
  1110.     10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,64,64,64,64,64,64,26,27,
  1111.     28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,
  1112.     64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  1113.     64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  1114.     64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  1115.     64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  1116.     64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  1117.     64,64,64,64,64,64,64,64,64,64,64,64,64
  1118. };
  1119.  
  1120. void uudecode(char *bufcoded, unsigned char *bufplain, int outbufsize) {
  1121.     int nbytesdecoded, j;
  1122.     register char *bufin = bufcoded;
  1123.     register unsigned char *bufout = bufplain;
  1124.     register int nprbytes;
  1125.     
  1126.     /* Strip leading whitespace. */
  1127.     
  1128.     while(*bufcoded==' ' || *bufcoded == '\t') bufcoded++;
  1129.     
  1130.     /* Figure out how many characters are in the input buffer.
  1131.      * If this would decode into more bytes than would fit into
  1132.      * the output buffer, adjust the number of input bytes downwards.
  1133.      */
  1134.     bufin = bufcoded;
  1135.     while(pr2six[*(bufin++)] <= 63);
  1136.     nprbytes = bufin - bufcoded - 1;
  1137.     nbytesdecoded = ((nprbytes+3)/4) * 3;
  1138.     if(nbytesdecoded > outbufsize) {
  1139.         nprbytes = (outbufsize*4)/3;
  1140.     }
  1141.     
  1142.     bufin = bufcoded;
  1143.     
  1144.     while (nprbytes > 0) {
  1145.         *(bufout++) = 
  1146.             (unsigned char) (pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4);
  1147.         *(bufout++) = 
  1148.             (unsigned char) (pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2);
  1149.         *(bufout++) = 
  1150.             (unsigned char) (pr2six[bufin[2]] << 6 | pr2six[bufin[3]]);
  1151.         bufin += 4;
  1152.         nprbytes -= 4;
  1153.     }
  1154.     
  1155.     if(nprbytes & 03) {
  1156.         if(pr2six[bufin[-2]] > 63)
  1157.             nbytesdecoded -= 2;
  1158.         else
  1159.             nbytesdecoded -= 1;
  1160.     }
  1161.     bufplain[nbytesdecoded] = '\0';
  1162. }
  1163.